/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_interval_strategy.cpp                                              *
 ****************************************************************************/

#include "elisa_interval_strategy.h"

USING_ELISA

//--------------------------------------------------------------------------
// class FactoryAndModel
//--------------------------------------------------------------------------
void FPNewtonFactory::create(ModelRep *mo, SetReduction & s)
{
	SetReduction s2;
	bool BC4 = true;
	AndModel *andModel = dynamic_cast<AndModel *>(mo);
	if (andModel != 0) {
		SetModelRep::iterator it;
		for (it = andModel->beginModel(); it != andModel->endModel(); ++it) {
			(*it)->createReductions(s2);
		}

		// Creation of fixed-point algorithm
		FixedPointReduction *fp = new FixedPointReduction(new SortQueue, 0);

		// INTERVAL NEWTON METHOD
		NewtonReductionFactory nwReduction(new NaturalIntervalFormFactory());
		nwReduction.create(mo, s2);

		fp->addReduction(s2);
		s.insert(fp);
	}
}


//--------------------------------------------------------------------------
// class FPFactory
//--------------------------------------------------------------------------
void FPFactory::create(ModelRep *mo, SetReduction & s)
{
	SetReduction s2;
	bool BC4 = true;
	AndModel *andModel = dynamic_cast<AndModel *>(mo);
	if (andModel != 0) {
		SetModelRep::iterator it;
		for (it = andModel->beginModel(); it != andModel->endModel(); ++it) {
			(*it)->createReductions(s2);
		}

		// Creation of fixed-point algorithm
		FixedPointReduction *fp = new FixedPointReduction(new SortQueue, 0);

		fp->addReduction(s2);
		s.insert(fp);
	}
}

//--------------------------------------------------------------------------
// class BoxReductionFactory
//--------------------------------------------------------------------------
void BC3ReviseFactory::create(RealConstraint & c,
                              RealVarImpl & x,
                              SetReduction & s)
{
	s.insert(new BoxReduction(&c, &x, _cons));
}

void BC3ReviseFactory::create(ModelRep *mo, SetReduction & s)
{
	ConstraintHandler *ch = dynamic_cast<ConstraintHandler *>(mo);
	if (ch != 0) {
		RealConstraint *constraint = dynamic_cast<RealConstraint *>(ch->getConstraint());
		if (constraint != 0) {
			VarImplSet::iterator it;
			for (it = constraint->beginVar(); it != constraint->endVar(); ++it) {
				RealVarImpl *x = dynamic_cast<RealVarImpl *>(it->get());
				if (x != 0) {
					this->create(*constraint, *x, s);
				}
			}
		}
	}
}

Reduction *BC3ReviseFactory::create(ModelRep *mo)
{
	SetReduction s;
	create(mo, s);
	FixedPointReduction *fp =
	    new FixedPointReduction(new SortQueue, 0);
	fp->addReduction(s);
	return fp;
}


//--------------------------------------------------------------------------
// class BC4
//--------------------------------------------------------------------------
void BC4Factory::create(ModelRep *mo, SetReduction & s)
{
	ConstraintHandler *ch = dynamic_cast<ConstraintHandler *>(mo);
	if (ch != 0) {
		BC3ReviseFactory bcf(new NaturalIntervalFormFactory());
		RealConstraint *constraint = dynamic_cast<RealConstraint *>(ch->getConstraint());
		if (constraint != 0) {
			bool hc4 = false;
			VarImplSet::iterator it;
			for (it = constraint->beginVar(); (it != constraint->endVar()); ++it) {
				if (constraint->multiplicity(**it) == 1) {
					hc4 = true;
				} else {
					RealVarImpl *x = dynamic_cast<RealVarImpl *>(it->get());
					if (x != 0) {
						bcf.create(*constraint, *x, s);
					}
				}
			}
			//we make only a HC4 for the constraint
			if (hc4) {
				HC4ReviseFactory hcf(new NaturalIntervalFormFactory());
				hcf.create(ch, s);
			}
		}
	}
}

//--------------------------------------------------------------------------
// class HullReductionFactory
//--------------------------------------------------------------------------

void HC4ReviseFactory::create(ModelRep *mo, SetReduction & s)
{
	ConstraintHandler *ch = dynamic_cast<ConstraintHandler *>(mo);
	if (ch != 0) {
		RealConstraint *constraint = dynamic_cast<RealConstraint *>(ch->getConstraint());
		if (constraint != 0) {
			s.insert(new HullReduction(constraint, _cons));
		}
	}
}


//--------------------------------------------------------------------------
// class NewtonReductionFactory
//--------------------------------------------------------------------------
void NewtonReductionFactory::create(ModelRep *mo, SetReduction & s)
{
	VarImplSet vars;
	SetConstraints constraints;

	AndModel *csp = dynamic_cast<AndModel *>(mo);
	if (csp != 0) {
		SetModelRep::iterator it;
		for (it = csp->beginModel(); it != csp->endModel(); ++it) {
			ConstraintHandler *ch = dynamic_cast<ConstraintHandler *>(*it);
			if (ch != 0) {
				RealConstraint *c = dynamic_cast<RealConstraint *>(ch->getConstraint());
				// c is a real constraint?
				if (c != 0) {
					// c is an equation?
					if (dynamic_cast<const RealConstraintRepEq *>(c->rep()) != 0) {
						VarImplSet::iterator iv;
						for (iv = c->beginVar(); iv != c->endVar(); ++iv) {
							vars.insert(*iv);
						}
						constraints.insert(c);
					}
				} else {
					this->create((*it), s);
				}
			}
		}

		// square system and at least 2 variables?
//#ifndef HYBRID
		if ((vars.size() == constraints.size()) && (vars.size() > 1)) {
//#else
		//if ((vars.size() == constraints.size() + 1) && (vars.size() > 1)) {
//#endif
			s.insert(new NewtonReduction(vars, constraints, _createForm));
		}
	}
}
